
# 导入 os 模块，用于与操作系统进行交互，处理文件路径等操作
import os
# 导入 json 模块，用于处理 JSON 数据的编码和解码
import json

# 从 qtpy 库导入 QtCore 和 QtGui 模块，提供 Qt 框架的核心功能和图形用户界面功能
from qtpy import QtCore, QtGui

# 从 src 核心的通用模块导入所有内容
from src.Core.Common import *
# 从 src 的输入模块导入输入动作、输入管理器和输入动作类型类
from src.Input import InputAction, InputManager, InputActionType

# 使用单例装饰器，确保 ConfigManager 类只有一个实例
@SingletonDecorator
class ConfigManager(object):
    """
    负责注册配置文件，通过别名对已注册的配置文件进行读写操作，
    并根据已注册的别名提供 QSettings 对象。
    """
    # 存储配置文件别名和对应绝对路径的字典
    CONFIGS_STORAGE = {}

    # 配置文件所在目录的绝对路径
    CONFIGS_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), "Configs")
    # 输入配置文件的绝对路径
    INPUT_CONFIG_PATH = os.path.join(CONFIGS_DIR, "input.json")

    def __init__(self, *args, **kwargs):
        # 注册偏好设置配置文件
        self.registerConfigFile("PREFS", os.path.join(self.CONFIGS_DIR, "prefs.ini"))
        # 注册应用状态配置文件
        self.registerConfigFile(
            "APP_STATE", os.path.join(self.CONFIGS_DIR, "config.ini")
        )

        # 检查输入配置文件是否存在
        if not os.path.exists(self.INPUT_CONFIG_PATH):
            # 若不存在，创建默认输入配置
            self.createDefaultInput()
            # 序列化输入管理器的配置数据
            data = InputManager().serialize()
            # 检查输入配置文件所在目录是否存在，若不存在则创建
            if not os.path.exists(os.path.dirname(self.INPUT_CONFIG_PATH)):
                os.makedirs(os.path.dirname(self.INPUT_CONFIG_PATH))
            # 将序列化后的数据写入输入配置文件
            with open(self.INPUT_CONFIG_PATH, "w") as f:
                json.dump(data, f)
        else:
            # 若输入配置文件存在，读取文件内容并加载到输入管理器中
            with open(self.INPUT_CONFIG_PATH, "r") as f:
                data = json.load(f)
                InputManager().loadFromData(data)

    @staticmethod
    def shouldRedirectOutput():
        """
        检查是否应该重定向输出。

        :return: 如果配置文件中设置应该重定向输出则返回 True，否则返回 False
        """
        return (
            ConfigManager().getPrefsValue("PREFS", "General/RedirectOutput") == "true"
        )

    def registerConfigFile(self, alias, absPath):
        """
        注册配置文件。

        :param alias: 配置文件的别名
        :param absPath: 配置文件的绝对路径
        :return: 如果注册成功返回 True，若别名已存在则返回 False
        """
        if alias not in self.CONFIGS_STORAGE:
            self.CONFIGS_STORAGE[alias] = absPath
            return True
        return False

    def getSettings(self, alias):
        """
        根据别名获取 QSettings 对象。

        :param alias: 配置文件的别名
        :return: 若别名存在，返回对应的 QSettings 对象；否则返回 None
        """
        if alias in self.CONFIGS_STORAGE:
            settings = QtCore.QSettings(
                self.CONFIGS_STORAGE[alias], QtCore.QSettings.IniFormat
            )
            return settings

    def getPrefsValue(self, configAlias, valueKey):
        """
        根据配置文件别名和值的键获取配置值。

        :param configAlias: 配置文件的别名
        :param valueKey: 配置值的键
        :return: 若配置存在，返回对应的值；否则返回 None
        """
        settings = self.getSettings(configAlias)
        if settings:
            if settings.contains(valueKey):
                return settings.value(valueKey)

    def createDefaultInput(self):
        """
        创建默认的输入配置，注册各种输入动作。
        """
        # 注册画布平移的鼠标输入动作（中键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.Pan",
                actionType=InputActionType.Mouse,
                group="Navigation",
                mouse=QtCore.Qt.MouseButton.MiddleButton,
            )
        )
        # 注册画布平移的鼠标输入动作（左键 + Alt 修饰键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.Pan",
                actionType=InputActionType.Mouse,
                group="Navigation",
                mouse=QtCore.Qt.MouseButton.LeftButton,
                modifiers=QtCore.Qt.AltModifier,
            )
        )
        # 注册画布缩放的鼠标输入动作（右键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.Zoom",
                actionType=InputActionType.Mouse,
                group="Navigation",
                mouse=QtCore.Qt.MouseButton.RightButton,
            )
        )
        # 注册画布聚焦选中元素的键盘输入动作（F 键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.FrameSelected",
                actionType=InputActionType.Keyboard,
                group="Navigation",
                key=QtCore.Qt.Key_F,
            )
        )
        # 注册画布聚焦所有元素的键盘输入动作（H 键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.FrameAll",
                actionType=InputActionType.Keyboard,
                group="Navigation",
                key=QtCore.Qt.Key_H,
            )
        )
        # 注册画布放大的键盘输入动作（Ctrl + = 键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.ZoomIn",
                actionType=InputActionType.Keyboard,
                group="Navigation",
                key=QtCore.Qt.Key_Equal,
                modifiers=QtCore.Qt.ControlModifier,
            )
        )
        # 注册画布缩小的键盘输入动作（Ctrl + - 键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.ZoomOut",
                actionType=InputActionType.Keyboard,
                group="Navigation",
                key=QtCore.Qt.Key_Minus,
                modifiers=QtCore.Qt.ControlModifier,
            )
        )
        # 注册画布重置缩放的键盘输入动作（Ctrl + R 键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.ResetScale",
                actionType=InputActionType.Keyboard,
                group="Navigation",
                key=QtCore.Qt.Key_R,
                modifiers=QtCore.Qt.ControlModifier,
            )
        )

        # 注册画布左对齐的键盘输入动作（Ctrl + Shift + 左方向键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.AlignLeft",
                actionType=InputActionType.Keyboard,
                group="Refactoring",
                modifiers=QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier,
                key=QtCore.Qt.Key_Left,
            )
        )
        # 注册画布上对齐的键盘输入动作（Ctrl + Shift + 上方向键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.AlignTop",
                actionType=InputActionType.Keyboard,
                group="Refactoring",
                modifiers=QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier,
                key=QtCore.Qt.Key_Up,
            )
        )
        # 注册画布右对齐的键盘输入动作（Ctrl + Shift + 右方向键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.AlignRight",
                actionType=InputActionType.Keyboard,
                group="Refactoring",
                modifiers=QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier,
                key=QtCore.Qt.Key_Right,
            )
        )
        # 注册画布下对齐的键盘输入动作（Ctrl + Shift + 下方向键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.AlignBottom",
                actionType=InputActionType.Keyboard,
                group="Refactoring",
                modifiers=QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier,
                key=QtCore.Qt.Key_Down,
            )
        )

        # 注册画布撤销操作的键盘输入动作（Ctrl + Z 键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.Undo",
                actionType=InputActionType.Keyboard,
                group="Editing",
                modifiers=QtCore.Qt.ControlModifier,
                key=QtCore.Qt.Key_Z,
            )
        )
        # 注册画布重做操作的键盘输入动作（Ctrl + Y 键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.Redo",
                actionType=InputActionType.Keyboard,
                group="Editing",
                modifiers=QtCore.Qt.ControlModifier,
                key=QtCore.Qt.Key_Y,
            )
        )
        # 注册画布删除选中元素的键盘输入动作（Delete 键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.KillSelected",
                actionType=InputActionType.Keyboard,
                group="Editing",
                key=QtCore.Qt.Key_Delete,
            )
        )
        # 注册画布复制节点的键盘输入动作（Ctrl + C 键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.CopyNodes",
                actionType=InputActionType.Keyboard,
                group="Editing",
                key=QtCore.Qt.Key_C,
                modifiers=QtCore.Qt.ControlModifier,
            )
        )
        # 注册画布剪切节点的键盘输入动作（Ctrl + X 键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.CutNodes",
                actionType=InputActionType.Keyboard,
                group="Editing",
                key=QtCore.Qt.Key_X,
                modifiers=QtCore.Qt.ControlModifier,
            )
        )
        # 注册画布拖动复制节点的鼠标输入动作（左键 + Alt 修饰键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.DragCopyNodes",
                actionType=InputActionType.Mouse,
                group="Editing",
                mouse=QtCore.Qt.MouseButton.LeftButton,
                modifiers=QtCore.Qt.AltModifier,
            )
        )
        # 注册画布拖动复制节点的鼠标输入动作（中键 + Alt 修饰键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.DragCopyNodes",
                actionType=InputActionType.Mouse,
                group="Editing",
                mouse=QtCore.Qt.MouseButton.MiddleButton,
                modifiers=QtCore.Qt.AltModifier,
            )
        )
        # 注册画布拖动节点的鼠标输入动作（中键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.DragNodes",
                actionType=InputActionType.Mouse,
                group="Editing",
                mouse=QtCore.Qt.MouseButton.MiddleButton,
            )
        )
        # 注册画布拖动节点的鼠标输入动作（左键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.DragNodes",
                actionType=InputActionType.Mouse,
                group="Editing",
                mouse=QtCore.Qt.MouseButton.LeftButton,
            )
        )
        # 注册画布拖动链式节点的鼠标输入动作（中键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.DragChainedNodes",
                actionType=InputActionType.Mouse,
                group="Editing",
                mouse=QtCore.Qt.MouseButton.MiddleButton,
            )
        )
        # 注册画布粘贴节点的键盘输入动作（Ctrl + V 键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.PasteNodes",
                actionType=InputActionType.Keyboard,
                group="Editing",
                key=QtCore.Qt.Key_V,
                modifiers=QtCore.Qt.ControlModifier,
            )
        )
        # 注册画布复制节点的键盘输入动作（Ctrl + D 键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.DuplicateNodes",
                actionType=InputActionType.Keyboard,
                group="Editing",
                key=QtCore.Qt.Key_D,
                modifiers=QtCore.Qt.ControlModifier,
            )
        )
        # 注册画布断开引脚连接的鼠标输入动作（左键 + Alt 修饰键）
        InputManager().registerAction(
            InputAction(
                name="Canvas.DisconnectPin",
                actionType=InputActionType.Mouse,
                group="Editing",
                mouse=QtCore.Qt.MouseButton.LeftButton,
                modifiers=QtCore.Qt.AltModifier,
            )
        )

        # 注册应用新建文件的键盘输入动作（Ctrl + N 键）
        InputManager().registerAction(
            InputAction(
                name="App.NewFile",
                actionType=InputActionType.Keyboard,
                group="IO",
                key=QtCore.Qt.Key_N,
                modifiers=QtCore.Qt.ControlModifier,
            )
        )
        # 注册应用保存文件的键盘输入动作（Ctrl + S 键）
        InputManager().registerAction(
            InputAction(
                name="App.Save",
                actionType=InputActionType.Keyboard,
                group="IO",
                key=QtCore.Qt.Key_S,
                modifiers=QtCore.Qt.ControlModifier,
            )
        )
        # 注册应用另存为文件的键盘输入动作（Ctrl + Shift + S 键）
        InputManager().registerAction(
            InputAction(
                name="App.SaveAs",
                actionType=InputActionType.Keyboard,
                group="IO",
                key=QtCore.Qt.Key_S,
                modifiers=QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier,
            )
        )
        # 注册应用加载文件的键盘输入动作（Ctrl + O 键）
        InputManager().registerAction(
            InputAction(
                name="App.Load",
                actionType=InputActionType.Keyboard,
                group="IO",
                key=QtCore.Qt.Key_O,
                modifiers=QtCore.Qt.ControlModifier,
            )
        )